import {
    Bus,
    CHART_CHAIN_SUBSCRIBE,
    CHART_KLINE_COMPLETE,
    CHART_KLINE_GOON,
    CHART_KLINE_SUBSCRIBE,
    CHART_KLINE_SUBSCRIBE_TIME,
    CHART_KLINE_UNSUBSCRIBE,
    CLOSE,
    CONN_ACTIVITY_RETRY,
    CONN_IMPORTANT,
    CONN_RETRY,
    CONN_STATUS,
    KLINE_RANK_FLUCTUATION_ALL,
    KLINE_RANK_WAVE,
    TOGGLE_PAUSE
} from "./Bus";
import { DayBroadcast } from "./DayBroadcast";
import { IBroadcast } from "./IBroadcast";
import { KlineBroadcast } from "./KlineBroadcast";
import { PingBroadcast } from "./PingBroadcast";
import { ActivityBroadcast } from "./ActivityBroadcast";
import { RankBroadcast } from "./RankBroadcast";
import { CleverBroadcast } from "./CleverBroadcast";
import { SignalBroadcast } from "./SignalBroadcast";
import { URL_SOCKET, URL_SOCKET_CHAIN } from "@/comm/api";
import { ActivityChainBroadcast } from "./ActivityChainBroadcast";
import { PingChainBroadcast } from "./PingChainBroadcast";
import { WaveBroadcast } from "./WaveBroadcast";
import { onDatas } from "./tooler";

// import { ImportantBroadcast } from "./ImportantBroadcast";

const compressed = true;
let lastRank = "";

export class Conn {
    static _instance: Conn;

    socket: WebSocket = null as any;
    chainSocket: WebSocket = null as any;
    // url = "ws://192.168.150.188:8088/websocket";
    broadcasts: IBroadcast[] = [];
    map: Map<string, IBroadcast> = new Map();
    chainMap: Map<string, IBroadcast> = new Map();

    static KEY_KLINE = "KLINE";
    static KEY_DAY = "TICKER";
    static KEY_PING = "pong";
    static KEY_ACTIVITY = "ON_CHAIN";
    static KEY_RANK = "COINS";
    static KEY_CLEVER = "CLEVER";
    static KEY_SIGNAL = "SIGNAL";
    static KEY_WAVE = "FLUCTUATION";

    // static KEY_IMPORTANT = "IMPORTANT"

    temp: any = null;
    timer = 0;
    retryTimes = 0;
    pause = false;
    isReady = false;

    maxAttempts = 5;
    currentAttempt = 0;
    lastTime = "";

    curSymbolName = "";
    curIntervalName = "";
    curAddress = "";

    constructor() {
        Bus.on(CHART_KLINE_SUBSCRIBE, (e: any) => {
            console.log("jsz", "CHART_KLINE_SUBSCRIBE");
            this.temp = e;
            this.init(e);
        });

        Bus.on(CHART_KLINE_COMPLETE, (e: any) => {
            console.log("jsz", "CHART_KLINE_COMPLETE");
            this.temp = e;
            this.init(e);
        });

        Bus.on(CHART_CHAIN_SUBSCRIBE, (e: any) => {
            (this.chainMap.get(Conn.KEY_ACTIVITY) as ActivityChainBroadcast).changeParam(e);
        });

        Bus.on(CHART_KLINE_UNSUBSCRIBE, () => {
            this.cancelKline();
        });

        Bus.on(KLINE_RANK_WAVE, (e: any) => {
            (this.map.get(Conn.KEY_WAVE) as WaveBroadcast).changeParam(e);
        });
        Bus.on(KLINE_RANK_FLUCTUATION_ALL, (e: any) => {
            console.log("改变时间");
            (this.map.get(Conn.KEY_WAVE) as WaveBroadcast).changeTime(e);
        });
        Bus.on(CHART_KLINE_GOON, e => {
            // (this.map.get(Conn.KEY_KLINE) as any).subscribe();
            console.log("参数 e", e);
            this.init(e);
        });

        Bus.on(CHART_KLINE_SUBSCRIBE_TIME, (e: any) => {
            // console.log("jsz", "change time",e,this.map.get(Conn.KEY_KLINE),Conn.KEY_KLINE);
            this.lastTime = e;
            (this.map.get(Conn.KEY_KLINE) as KlineBroadcast).changeInterval(e);
        });

        Bus.on(CONN_RETRY, () => {
            this.retryTimes = 0;
            this.start();
        });

        Bus.on(TOGGLE_PAUSE, (e: any) => {
            // this.pause = !this.pause;
            this.currentAttempt = 2;
            this.chainSocket.close();
            this.socket.close();
            // alert("暂停");
        });

        Bus.on(CONN_ACTIVITY_RETRY, (e: any) => {
            // console.log("aaaa=====================", "CONN_ACTIVITY_RETRY");
            this.chainMap.get(Conn.KEY_ACTIVITY)!.subscribe();
        });

        this.map = new Map();
        this.map.set(Conn.KEY_KLINE, new KlineBroadcast());
        this.map.set(Conn.KEY_DAY, new DayBroadcast());
        this.map.set(Conn.KEY_PING, new PingBroadcast());
        // this.map.set(Conn.KEY_ACTIVITY, new ActivityBroadcast());
        this.map.set(Conn.KEY_RANK, new RankBroadcast());
        this.map.set(Conn.KEY_CLEVER, new CleverBroadcast());
        this.map.set(Conn.KEY_SIGNAL, new SignalBroadcast());
        this.map.set(Conn.KEY_WAVE, new WaveBroadcast());

        this.chainMap = new Map();
        this.chainMap.set(Conn.KEY_ACTIVITY, new ActivityChainBroadcast());
        this.chainMap.set(Conn.KEY_PING, new PingChainBroadcast());
    }

    changeCoin(coin: string) {
        (this.map.get(Conn.KEY_KLINE) as any).changeCoin(coin);
        (this.map.get(Conn.KEY_DAY) as any).changeCoin(coin);
    }

    init(e: any) {
        this.curSymbolName = e.symbol;
        this.curIntervalName = e.interval;
        (this.map.get(Conn.KEY_KLINE) as any).changeParam(e.symbol, e.interval);
        (this.map.get(Conn.KEY_DAY) as any).changeParam(e.symbol);
        (this.map.get(Conn.KEY_SIGNAL) as any).changeParam(e.symbol);
        // (this.chainMap.get(Conn.KEY_ACTIVITY) as ActivityChainBroadcast).changeParam(e.symbol);
    }

    addChannel(broadcast: IBroadcast) {
        this.broadcasts.push(broadcast);
    }

    cancelKline() {
        (this.map.get(Conn.KEY_KLINE) as any).unSubscribe();
    }

    homeSubscribe(val: boolean) {
        if (this.socket) {
            try {
                if (val) {
                    this.socket.send(JSON.stringify({ event: "subscribe", group: "ALL", topic: "COINS" }));
                }
                else {
                    this.socket.send(JSON.stringify({ event: "unsubscribe", group: "ALL", topic: "COINS" }));
                }
            }
            catch (e) {
                console.log("socket no connect");
            }
        }
    }

    rankSubscribe(val: boolean, type: string) {
        if (this.socket) {
            try {
                lastRank && this.socket.send(JSON.stringify({ event: "unsubscribe", group: lastRank, topic: "COINS" }));
                if (val) {
                    lastRank = type;
                    this.socket.send(JSON.stringify({ event: "subscribe", group: type, topic: "COINS" }));
                }
                else {
                    this.socket.send(JSON.stringify({ event: "unsubscribe", group: lastRank, topic: "COINS" }));
                }
            }
            catch (e) {
                console.log("socket no connect");
            }
        }
    }

    waitSocket(url: string) {
        return new Promise<WebSocket>(resolve => {
            let socket = new WebSocket(url);
            socket.onopen = ev => {
                Bus.emit(CONN_STATUS, 1);
                console.warn("链接成功 ====", socket.readyState);
                this.retryTimes = 0;
                this.currentAttempt = 0;
                resolve(socket);
            }
        })
    }


    start() {
        return new Promise(async resolve => {
            console.log("初始化socket定义");
            // if (++this.retryTimes > 3) {
            //     Bus.emit(CONN_STATUS, 3);
            //     return;
            // }

            ++this.currentAttempt;
            // if(this.socket){
            //     this.socket.close();
            // }
            console.log(this.retryTimes, "開始鏈接socket"); 
            this.socket?.close();
            this.chainSocket?.close();

            Bus.emit(CONN_STATUS, 0);

            // this.socket = new WebSocket(URL_SOCKET);
            // this.chainSocket = new WebSocket(URL_SOCKET_CHAIN);
            this.socket = await this.waitSocket(URL_SOCKET);
            this.map.get(Conn.KEY_PING)!.subscribe();
            this.map.get(Conn.KEY_RANK)!.subscribe();
            this.map.get(Conn.KEY_SIGNAL)!.subscribe();
            this.map.get(Conn.KEY_DAY)!.subscribe();
            (this.map.get(Conn.KEY_KLINE) as KlineBroadcast).changeParam(this.curSymbolName, this.curIntervalName);
            this.map.get(Conn.KEY_WAVE)!.subscribe();

            this.homeSubscribe(location.href.includes("ranks") == false);

            this.chainSocket = await this.waitSocket(URL_SOCKET_CHAIN);
            this.chainMap.get(Conn.KEY_PING)!.subscribe();
            this.chainMap.get(Conn.KEY_ACTIVITY)!.subscribe();

            resolve(true);
            this.timer = Date.now();

            setTimeout(() => {
                if (this.socket.readyState == 0) {
                    this.start();
                }
            }, 5000);

            // this.socket.onopen = ev => {
            //     Bus.emit(CONN_STATUS, 1);
            //     this.currentAttempt = 0;
            //     this.map.get(Conn.KEY_PING)!.subscribe();
            //     this.map.get(Conn.KEY_RANK)!.subscribe();
            //     this.map.get(Conn.KEY_SIGNAL)!.subscribe();
            //     this.map.get(Conn.KEY_DAY)!.subscribe();
            //     (this.map.get(Conn.KEY_KLINE) as KlineBroadcast).changeParam(this.curSymbolName, this.curIntervalName);
            //     this.map.get(Conn.KEY_WAVE)!.subscribe();
            // };

            // this.chainSocket.onopen = ev => {
            //     this.chainMap.get(Conn.KEY_PING)!.subscribe();
            //     this.chainMap.get(Conn.KEY_ACTIVITY)!.subscribe();
            //     resolve(true);
            // };

            this.socket.onclose = ev => {
                Bus.emit(CONN_STATUS, 3);
                for (let item of this.map.values()) {
                    item.unSubscribe();
                }

                if (this.currentAttempt < this.maxAttempts) {
                    console.log(`Reconnecting (attempt ${this.currentAttempt} of ${this.maxAttempts})`);
                    setTimeout(() => this.start(), 5000); // 5秒后尝试重新连接
                } else {
                    // alert('连接失败');
                    console.log("Max connection attempts reached. Connection failed.");
                    Bus.emit(CONN_STATUS, 3);
                }
            };

            this.socket.onerror = ev => {
                this.socket.close();
                Bus.emit(CONN_STATUS, 3);

            };

            this.chainSocket.onerror = ev => {
                this.chainSocket.close();
                Bus.emit(CONN_STATUS, 3);

            };

            // this.socket.binaryType = "arraybuffer";
            this.socket.onmessage = async (ev) => {
                var data = ev.data;
                // console.log("sso", data,ev);

                if (this.pause) return;

                if (compressed) {
                    // data = (window as any).pako.inflate(data, { to: "string" });
                    data = await onDatas(data);
                }

                if (data == "pong") {
                    this.map.get(Conn.KEY_PING)!.handle("");
                    return;
                }


                var jsondata = JSON.parse(data);
                const broadcast = this.map.get(jsondata.topic);
                if (broadcast) {
                    broadcast.handle(jsondata);
                    // console.log(jsondata,"jsondatajsondatajsondata111");
                    
                }
            };

            this.chainSocket.onmessage = async (ev) => {
                var data = ev.data;
                // console.log("ggg", data,ev);

                if (this.pause) return;

                if (compressed) {
                    // data = (window as any).pako.inflate(data, { to: "string" });
                    data = await onDatas(data);
                }

                if (data == "pong") {
                    this.chainMap.get(Conn.KEY_PING)!.handle("");
                    return;
                }

                var jsondata = JSON.parse(data);
                const broadcast = this.chainMap.get(jsondata.topic);
                if (broadcast) {
                    broadcast.handle(jsondata);
                    // console.log(jsondata,"jsondatajsondatajsondata222");

                }
            };
        });
    }

    static get ins(): Conn {
        // console.log("ins");
        if (!Conn._instance) {
            Conn._instance = new Conn();
        }
        return Conn._instance;
    }
}

function getString(blob: any) {
    return new Promise(resolve => {
        if (typeof blob == "string") {
            resolve(blob);
            return;
        }
        /*
        const reader = new FileReader();

        // 设置 onload 事件处理程序
        reader.onload = function (event: any) {
            // 从 result 属性中获取 ArrayBuffer
            const arrayBuffer = event.target.result;

            // 将 ArrayBuffer 转换为 Uint8Array
            const uint8Array = new Uint8Array(arrayBuffer);

            // 现在你可以使用 uint8Array 进行操作
            // console.log(uint8Array);
           
            let str = (window as any).pako.inflate(uint8Array, { to: "string" });
            resolve(str);
        };

        // 读取 Blob 中的数据为 ArrayBuffer
        reader.readAsArrayBuffer(blob);
        */
        try {
            const textDecoder = new TextDecoder('utf-8'); // 指定编码方式，例如 utf-8
            // (window as any).pako.ungzip(blob);
            // let res = (window as any).pako.inflate(blob, { raw: true });
            const decodedString = textDecoder.decode(blob);
            resolve(decodedString);
        }
        catch (e) {
            console.log("pppinggg", e);
        }
        // console.log(decodedString); // 输出 "Hello"
    });
}
